---
--类名: RotateMenu.lua
--创建日期: 2016-6-14
--创建人: 陈小虎
--功能描述: 旋转菜单
--修改内容:
--修改日期:   
--修改人:     
--修改备注: 
--
local RotateMenu = class("RotateMenu",function()
	return display.newLayer()
end)

local PI = math.acos(-1)
local DURATION = 0.3

function RotateMenu:ctor()
	self._items = {}
	self.animationDuration = 0.3
	self._angle = 0.0
	self._unitAngle = 0.0
	self:ignoreAnchorPointForPosition(false)
	self._selectedItem = nil
	local s = cc.Director:getInstance():getWinSize()
	self:setContentSize(cc.size(s.width / 3 * 2,s.height / 3 * 2))
	self:setAnchorPoint(cc.p(0.5,0.5))

	self._beganPos = cc.p(0,0)

	local function touchBegan(touch, event)
		self._beganPos = touch:getLocation()
		local target = event:getCurrentTarget()
		local position = target:convertToNodeSpace(touch:getLocation())
		local size = target:getContentSize()
		local rect = cc.rect(0, 0, size.width, size.height)
		if cc.rectContainsPoint(rect, position) and not self:isStopTouch() then
			for i,v in ipairs(self._items) do
				v:stopAllActions()
			end
			return true
		end
		return false
	end
	local function touchMoved(touch, event)
		if math.abs(touch:getLocation().x - self._beganPos.x) <= 10 then return end
		if self._selectedItem then
			self._selectedItem:unselected()
		end
		local angle = self:disToAngle(touch:getDelta().x)
		self:setAngle(self:getAngle() + angle)
		self:updatePosition()
	end
	local function touchEnded(touch, event)
		local xDelta = touch:getLocation().x - touch:getStartLocation().x
		self:rectify(xDelta > 0)
		if self:disToAngle(math.abs(xDelta)) < self:getUnitAngle() / 6 and self._selectedItem then
			self._selectedItem:activate()
		end
		self:updatePositionWithAnimation()
	end

    local listener = cc.EventListenerTouchOneByOne:create()
    listener:setSwallowTouches(false)
    listener:registerScriptHandler(touchBegan,cc.Handler.EVENT_TOUCH_BEGAN)
    listener:registerScriptHandler(touchMoved,cc.Handler.EVENT_TOUCH_MOVED)
    listener:registerScriptHandler(touchEnded,cc.Handler.EVENT_TOUCH_ENDED)
    self:getEventDispatcher():addEventListenerWithSceneGraphPriority(listener, self)
end

function RotateMenu:setAnimationDuration(duration)
	self.animationDuration = duration
end

function RotateMenu:resetAnimationDuration()
	self.animationDuration = DURATION
end

function RotateMenu:addMenuItem(item)
	item:setPosition(cc.p(self:getContentSize().width / 2,self:getContentSize().height / 2))
	self:addChild(item)
	table.insert(self._items,item)
	self:setUnitAngle(2 * PI / (#self._items))
	self:reset()
	self:updatePositionWithAnimation()
end

function RotateMenu:runDelayTouchAction()
	self._delayAction = cc.Sequence:create(cc.DelayTime:create(self.animationDuration),cc.CallFunc:create(function()
	    self._delayAction = nil
	    self:stopTouch(false)
	end))
	self:runAction(self._delayAction)
	self:stopTouch(true)
end

function RotateMenu:isRunDelayAction()
	return self._delayAction
end

function RotateMenu:select(idx)
	if idx <= #self._items then
    	if self:isRunDelayAction() then return end

    	self:runDelayTouchAction()

		local _,curIndex = self:getCurrentItem()
		if curIndex == idx then return end
		if self._selectedItem then
			self._selectedItem:unselected()
		end

		local disAngle = curIndex - idx
		local angle = self:getAngle() + disAngle * self:getUnitAngle()

		angle = self:rightAngle(angle)

		self:setAngle(angle)
		self:updatePositionWithAnimation()
	end
end

function RotateMenu:rightAngle(angle)
	while angle < 0 
	do
		angle = angle + PI * 2
	end
	while angle > PI * 2
	do
		angle = angle - PI * 2
	end
	return angle
end

function RotateMenu:rotateToNext(dir)
    if self:isRunDelayAction() then return end

    self:runDelayTouchAction()

	if self._selectedItem then
		self._selectedItem:unselected()
	end
	local angle = 0

    if dir == 0 then
    	angle = self:getAngle() - self:getUnitAngle()
    else
    	angle = self:getAngle() + self:getUnitAngle()
    end

	angle = self:rightAngle(angle)

    self:setAngle(angle)
    self:updatePositionWithAnimation()
end

function RotateMenu:reset()
	self._angle = 0
end

function RotateMenu:setAngle(angle)
	self._angle = angle
end

function RotateMenu:getAngle()
	return self._angle
end

function RotateMenu:setUnitAngle(angle)
	self._unitAngle = angle
end

function RotateMenu:getUnitAngle()
	return self._unitAngle
end

function RotateMenu:disToAngle(dis)
	local width = self:getContentSize().width / 2
	return dis / width * self:getUnitAngle()
end

function RotateMenu:getCurrentItem()
	if #self._items == 0 then return nil end
	local index = math.floor((2 * PI - self:getAngle()) / self:getUnitAngle() + 0.1 * self:getUnitAngle())
	index = index % (#self._items)
	index = index + 1
	return self._items[index],index
end

function RotateMenu:rectify(forward)
	local angle = self:getAngle()
	while angle < 0 
	do
		angle = angle + PI * 2
	end
	while angle > PI * 2
	do
		angle = angle - PI * 2
	end

	if forward then
		angle = math.floor(((angle + self:getUnitAngle() / 3 * 2) / self:getUnitAngle())) * self:getUnitAngle()
	else
		angle = math.floor(((angle + self:getUnitAngle() / 3 ) / self:getUnitAngle())) * self:getUnitAngle()
	end
	self:setAngle(angle)
end

function RotateMenu:actionEndCallBack(dx)
	self._selectedItem = self:getCurrentItem()
	if self._selectedItem then
		self._selectedItem:selected()
	end
	self:actionEndCallback()
end

function RotateMenu:setActionEndCallback(callback)
	self._endCallback = callback
end

function RotateMenu:actionEndCallback()
	if self._endCallback then
		self._endCallback()
	end
end

function RotateMenu:updatePosition()
	for i,v in ipairs(self._items) do
		v:stopAllActions()
	end
	local menuSize = self:getContentSize()
	local disY = menuSize.height / 8
	local disX = menuSize.width / 3
	for i,v in ipairs(self._items) do
		local x = menuSize.width / 2 + disX * math.sin((i - 1) * self._unitAngle + self:getAngle())
		local y = menuSize.height / 2 - disY * math.cos((i - 1) * self._unitAngle + self:getAngle())
		v:setPosition(cc.p(x,y))
		v:setLocalZOrder(-math.floor(y))
		local color = 192 + 63 * math.cos((i - 1) * self._unitAngle + self:getAngle())
		v:setColor(cc.c3b(color,color,color))
		v:setScale(0.75 + 0.25 * math.cos((i - 1) * self._unitAngle + self:getAngle()))
	end
end

function RotateMenu:updatePositionWithAnimation()
	for i,v in ipairs(self._items) do
		v:stopAllActions()
	end
	local menuSize = self:getContentSize()
	local disY = menuSize.height / 8
	local disX = menuSize.width / 3
	for i,v in ipairs(self._items) do
		local x = menuSize.width / 2 + disX * math.sin((i - 1) * self._unitAngle + self:getAngle())
		local y = menuSize.height / 2 - disY * math.cos((i - 1) * self._unitAngle + self:getAngle())
		local moveTo = cc.MoveTo:create(self.animationDuration,cc.p(x,y))
		v:runAction(moveTo)
		-- local fadeTo = cc.FadeTo:create(self.animationDuration,192 + 63 * math.cos(i * self._unitAngle + self:getAngle()))
		-- v:runAction(fadeTo)
		local color = 192 + 63 * math.cos((i - 1) * self._unitAngle + self:getAngle())
		v:setColor(cc.c3b(color,color,color))
		local scaleTo = cc.ScaleTo:create(self.animationDuration,0.75 + 0.25 * math.cos((i - 1) * self._unitAngle + self:getAngle()))
		v:runAction(scaleTo)
		v:setLocalZOrder(-math.floor(y))
	end
	-- self:stopAllActions()
	local action = cc.Sequence:create(cc.DelayTime:create(self.animationDuration),cc.CallFunc:create(handler(self,RotateMenu.actionEndCallBack)))
	self:runAction(action)
	-- local scheduler = cc.Director:getInstance():getScheduler()
	-- local schedulerID = nil
	-- schedulerID = scheduler:scheduleScriptFunc(function()
	   
	-- end,0,false)   
end

function RotateMenu:stopTouch(isStop)
	self._stopTouch = isStop
end

function RotateMenu:isStopTouch()
	return self._stopTouch
end

return RotateMenu